/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#include "renderqueue.h"
#include "material.h"
#include "camera.h"

#include <algorithm>
#include <limits>

namespace Engine
{
	using namespace std;
	/******************************************************************************************************/
	RenderQueue::RenderQueue()
	{
	}
	/******************************************************************************************************/
	RenderQueue::~RenderQueue()
	{
	}
	/******************************************************************************************************/
	void RenderQueue::AddRenderable(RenderablePtr rend)
	{
		m_addMutex.Lock();
		if(rend->GetMaterial()->IsTransparent())
		{
			RenderableVector vec(1,rend);
			m_transparents.insert(RenderableGroupMultiMap::value_type(rend->GetMaterial()->GetName(),vec));
		}
		else
		{
			m_solids[rend->GetMaterial()->GetName()].push_back(rend);
		}
		m_addMutex.Unlock();
	}
	/******************************************************************************************************/
	void RenderQueue::Reset()
	{
		m_solids.clear();
		m_transparents.clear();
	}
	/******************************************************************************************************/
	void RenderQueue::Sort(const Camera* camera)
	{
		if(camera != 0)
		{						
			//sort transparents
			SortTransparents(m_transparents, m_sortTransparents, camera);
			
			//sort solids
			SortGroup(m_solids, m_sortSolids, camera);
		}
	}
	/******************************************************************************************************/
	void RenderQueue::SortGroup(RenderableGroupMap& group, RenderableSortGroupVector& sortGroup, const Camera* camera, bool less)
	{
		RenderableGroupMap::iterator i = group.begin(), e = group.end();		
		sortGroup.clear();
		for(;i != e; ++i)
		{
			sortGroup.push_back(RenderableSortGroup(0,i->first,&i->second));
		}		
	}
	/******************************************************************************************************/
	void RenderQueue::SortTransparents(RenderableGroupMultiMap& group, RenderableSortGroupVector& sortGroup, const Camera* camera)
	{
		RenderableGroupMultiMap::iterator i = group.begin(), e = group.end();
		// sort objects with distances 
		sortGroup.clear();
		for(;i != e; ++i)
		{
			REAL minLen = 0; 
			Vector3<REAL> pos(i->second[0]->GetWorldTransform()[0][3],i->second[0]->GetWorldTransform()[1][3],i->second[0]->GetWorldTransform()[2][3]);
			minLen = (camera->GetPosition() - pos).Length();
		
			sortGroup.push_back(RenderableSortGroup(minLen,i->first,&i->second));
		}
		// sort groups with smallest distances 
		sort(sortGroup.begin(),sortGroup.end());
	}
	/******************************************************************************************************/
	const RenderQueue::RenderableSortGroupVector& RenderQueue::GetSolids()const
	{
		return m_sortSolids;
	}
	/******************************************************************************************************/
	const RenderQueue::RenderableSortGroupVector& RenderQueue::GetTransparents()const
	{
		return m_sortTransparents;
	}
	/******************************************************************************************************/
}
